
#include "rtmp_server.h"
#include "connection.h"
#include "loop_event.hpp"
#include "message_logic.h"
#include "rtmp_message.h"
#include "server.h"
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <memory>
#include <netinet/in.h>
#include "media_source_manager.h"

RtmpServer::RtmpServer(LoopEvent * loop)
{
    m_loop_event = loop;
    m_media_source_manager = std::make_shared<MediaSourceManager>();
}

void RtmpServer::StartServer(int port)
{
    m_server = std::make_shared<Server>(m_loop_event);
    m_server->SetOnConnectionFunc([this](Connection * connection){

        if (m_connection)
        {
            m_connection.reset();
        }    
        printf("line : %d function : %s new connection.\n", __LINE__, __func__);
        m_connection = std::make_shared<RtmpConnection>(m_loop_event, connection, this);
    });
    m_server->SetOnMessageFunc([this](Connection * connection, const uint8_t * data, int data_length){
        
        if (m_connection)
        {
            ConnectionData msg;
            msg.m_data = data;
            msg.m_data_length = data_length;
            m_connection->ProcessMessage(connection, msg);

        }    
    });
    m_server->Listen(port);
}

std::shared_ptr<MediaSourceManager> RtmpServer::GetMediaSourceMgr()
{
    return m_media_source_manager;
}

RtmpConnection::RtmpConnection(LoopEvent * loop, Connection * connection, RtmpServer * server)
{
    m_loop_event = loop;
    m_connection = connection;
    m_status     = EmConnected;
}


void RtmpConnection::ProcessMessage(Connection * connection, ConnectionData & data)
{
    if (m_status == EmConnected)
    {
        int index = 0;
        uint8_t version = data.m_data[index];
        if (version == 0x03 && data.m_data_length >= (1537))
        {
            index++;
            uint32_t time = 0;
            memcpy(&time, &data.m_data[index], sizeof(time));
            time = htonl(time);
            printf("client c1 time : %d.\n", time);
            data.m_send_msg.resize(1536 + 1);
            data.m_send_msg[0] = 0x03;
            memcpy(&(*(data.m_send_msg.begin() + 1)), &time, sizeof(time));
            for (int index = 5; index < (5 + 4); index++)
            {
                data.m_send_msg[index] = 0;
            }
            memcpy(&(*(data.m_send_msg.begin() + 9)), (data.m_data + 9 + 9), 1528);
            data.m_send_msg_length = 1537;
            printf("send s0s1 length : %d.\n", data.m_send_msg_length);
            m_connection->SendData(data.m_data, data.m_data_length);
            m_connection->SendData(data.m_data + 1, data.m_data_length - 1);
            m_status = EmConnHandshakeC0C1;
            m_connection->RemoveBufferData(data.m_data_length);
            /* m_connection->SendData(data.data + 1, data.m_data_length - 1); */
        }
        else
        {
            m_connection->CloseConnection();
            m_connection = nullptr;   
        }
    }
    else if (m_status == EmConnHandshakeC0C1)
    {
        printf("recv c2 message length : %d.\n", data.m_data_length);
        /* m_connection->SendData(data.m_data, data.m_data_length); */
        m_connection->RemoveBufferData(data.m_data_length);
        m_status = EmConnHandshakeSuc;
    }
    else if (m_status == EmConnHandshakeSuc)
    {
        int length = 0;
        do
        {
            RtmpPacketMsg request;
            int parse_size = request.PushData(data.m_data + length, data.m_data_length - length);
            if (request.IsComplete())
            {
                RtmpPacketMsg response;
                int result = m_logic.ProcessRtmpMsg(request, response);
                if (result == 0)
                {
                    ProcessSendData(response);
                    for (auto & msg : response.m_rtmp_msg_vec)
                    {
                        ProcessSendData(msg);
                    }
                }
                length+=parse_size;
            }
            else
            {
                break;
            }
        }while(true);
        if (length > 0)
            m_connection->RemoveBufferData(length);
    }
    else
    {
        printf("connection status : %d.\n", m_status);
    }   
}

void RtmpConnection::ProcessSendData(RtmpPacketMsg & response)
{
    /* int body_size = response.m_header.m_body_size; */
    int index = 0;
    uint8_t data[1024];
    memset(data, 0, sizeof(data));
    int compose_length = 0;
    int chunk_size = 128;
    response.m_header.ComposeDataToBuffer(data, sizeof(data), compose_length);
    int body_size = response.m_header.m_body_size;
    printf("compose length data : %d and body size : %d.\n", compose_length, body_size);
    while (1)
    {
        uint8_t format = data[index] >> 6;
        int header_size = format == 0 ? 12 : (format == 1 ? 8 : (format == 2 ? 4 : 1));
        if (chunk_size > body_size)
        {
            chunk_size = body_size;
        }
        int chunk_block_size = chunk_size + header_size;
        int send_size = m_connection->SendData(data + index, chunk_block_size);
        printf("send data size : %d.\n", send_size);
        /* compose_length -= chunk_block_size; */
        body_size -= chunk_size;
        index += chunk_block_size;
        data[index - 1] = 0xc3;
        index -= 1;
        if (body_size <= 0)
        {
            break;
        }
    }
}
